package expression;


import build.Bin.ClassFuncRun;
import build.Bin.Function;
import vm.baseNativeUseFunction.NativeUseFunction;
import vm.runtime.NextVMRuntime;

import javax.naming.Name;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class MathExpression {
    public static Pattern pattern_eval_math = Pattern.compile("((?<=\\+)|(?=\\+))|((?<=-)|(?=-))|((?<=\\*)|(?=\\*))|((?<=/)|(?=/))|((?<=\\()|(?=\\())|((?<=\\))|(?=\\)))");
    public static Pattern pattern_math_exp = Pattern.compile("(?=[+\\-*/()])|(?<=[+\\-*/()])");
    public static Pattern splitMath = Pattern.compile("(?=[+\\-*/()])|(?<=[+\\-*/()])");

    private static List<String> processArray(String[] array) throws Exception{
        List<String> resultList = new ArrayList<>();
        StringBuilder currentExpression = new StringBuilder();

        for (int i = 0; i < array.length; i++) {
            String current = array[i];
            // 检查当前元素是否是左括号，并且前一个元素不是运算符
            if ("(".equals(current) && i > 0 && !isOperator(array[i - 1])) {
                // 将左括号与前一个元素合并
                currentExpression.append(array[i - 1]).append(current);
            } else if (")".equals(current) && !currentExpression.isEmpty()) {
                // 如果当前元素是右括号并且currentExpression不为空，则闭合表达式
                currentExpression.append(current);
                resultList.add(currentExpression.toString());
                currentExpression.setLength(0); // 重置StringBuilder

            } else if (currentExpression.isEmpty()) {
                // 如果currentExpression为空，直接添加当前元素
                resultList.add(current);
            } else {
                // 如果currentExpression不为空，追加当前元素
                currentExpression.append(current);
            }
        }

        return resultList;
    }

    private static boolean isOperator(String str) {
        return "+".equals(str) || "-".equals(str) || "*".equals(str) || "/".equals(str);
    }
    /*
    private static List<String> formatArrays(List<String> arr) {
        ArrayList<String> format = new ArrayList<>(arr);
        for (int i = 0 ; i < arr.size() ;i++) {
            String item = arr.get(i).trim();
            if (item.isEmpty()) {
                continue;
            }
            else if (
                    !StringExpression.IsNumber(item) &&
                            !isOperator(item ) &&
                            (!item.contains("(") && !item.contains(")"))
                            && i < arr.size()-1
            ) {
                String NextItem = arr.get(i+1);
                if (NextItem.contains("(") && NextItem.contains(")")) {
                    String NextName = NextItem.substring(0,NextItem.indexOf("(")).trim();
                    if (NextName.equals(item)) {
                        format.remove(i);
                    }
                }
                continue;
            }
            else if (item.contains("(") && item.contains(")")) {
                continue;
            }else if (isOperator(item)) {
                continue;
            } else if (item.contains("(") || item.contains(")")) {
                continue;
            }
        }
        return format;
    }
    */
    private static List<String> formatArrays(List<String> arr) throws Exception {
        return arr.stream()
                .map(String::trim) // 去除每个元素的空白字符
                .filter(item -> !item.isEmpty()) // 过滤掉空字符串
                .filter(item -> {
                    if (StringExpression.IsNumber(item) || isOperator(item) || item.contains("(") || item.contains(")")) {
                        return true; // 如果是数字、操作符或者包含括号，保留
                    }
                    // 检查当前项和下一项是否符合特定条件
                    int index = arr.indexOf(item);
                    if (index < arr.size() -1) {
                        String nextItem = arr.get(index + 1);
                        if (nextItem.contains("(") && nextItem.contains(")")) {
                            String nextName = nextItem.substring(0, nextItem.indexOf("(")).trim();
                            return !item.equals(nextName); // 如果当前项等于下一项的函数名，则过滤掉
                        }
                    }
                    return true;
                })
                .collect(Collectors.toCollection(ArrayList::new)); // 收集结果到ArrayList
    }

    public static double evaluateExpression(String expression , NextVMRuntime nextVMRuntime)
            throws Exception {
        StringBuffer stringBuffer = new StringBuffer();
        String[] exp = splitMath.split(expression);
        List<String> processedArray = formatArrays(processArray(exp));
        try {
            // "((?<=\\+)|(?=\\+))|((?<=-)|(?=-))|((?<=\\*)|(?=\\*))|((?<=/)|(?=/))|((?<=\\()|(?=\\())|((?<=\\))|(?=\\)))"
            for (String string : processedArray) {
                String s = string;
                if (s.isEmpty()) {
                    continue;
                }
                Object value = StringExpression.getValueFromNextVM(s, nextVMRuntime);
                if (value != null) {
                    stringBuffer.append(value);
                    continue;
                } else if (NativeUseFunction.IsNativeUseFunctionCode(s)) {
                    String[] tokens = {"system_time"};
                    stringBuffer.append(NativeUseFunction.run(tokens, nextVMRuntime, "system_time()"));
                    continue;
                } else if (isList(s, nextVMRuntime, stringBuffer)) {
                    continue;
                }
                NextVMRuntime UseFunction = CodeFunctionFromRuntime(s, nextVMRuntime);
                if (UseFunction != null) {
                    UseFunction.run();
                    stringBuffer.append(UseFunction.ReturnContent);
                    continue;
                } else {
                    stringBuffer.append(s);
                }
            }
            //System.out.println(stringBuffer.toString().trim()+";");
            return RealEvaluateExpression(stringBuffer.toString().trim());
        } catch (Exception e) {
            //e.printStackTrace();
            throw new Exception(e);
        }
    }
    public static NextVMRuntime CodeFunctionFromRuntime(String code , NextVMRuntime nextVMRuntime) {
        try {
            String Name = code.substring(0 , code.indexOf("(")).trim();
            NextVMRuntime UserDefineFunc = NextVMRuntime.getFunctionFromRuntime(Name , nextVMRuntime);
            if (UserDefineFunc != null) {
                return UserDefineFunc;
            }else if (Name.contains(".")) {
                String ClassName = Name.substring(0,Name.indexOf(".")).trim();
                String Invoke = Name.substring(Name.indexOf(".")+1).trim();

                String Content = code.substring(code.indexOf("(")+1,code.lastIndexOf(")")).trim();
                String regex = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)(?=([^\\(]*\\([^\\)]*\\))*[^\\)]*$)";
                String[] split = Content.split(regex);

                NextVMRuntime ClassFunc = (NextVMRuntime) nextVMRuntime.values.get(ClassName);
                //System.out.println(ClassFunc.Functions.get(Invoke).FunctionInputValue);
                NextVMRuntime fn = ClassFunc.Functions.get(Invoke);
                Function.putInputFunction(Invoke ,fn , ClassFunc , split);
                return ClassFunc.Functions.get(Invoke);
            }else {
                return null;
            }
        }catch (Exception e) {
            return null;
        }
    }

    private static boolean isList(String code , NextVMRuntime nextVMRuntime,StringBuffer stringBuffer) throws Exception {
        String value = null;
        String input = null;
        try {
            value = code.substring(0 , code.indexOf("[")).trim();
            input = code.substring(code.indexOf("[")+1 , code.length() -1).trim();
            Object object = StringExpression.getValueFromNextVM(value , nextVMRuntime);
            if (object != null) {
                int index = (int) MathExpression.evaluateExpression(input , nextVMRuntime);
                ArrayList<Object> arrayList = (ArrayList<Object>) object;
               // System.out.println(arrayList.size()+" "+arrayList);
                stringBuffer.append((int) arrayList.get(index));
            } else {
                throw new Exception("Unknown Value: "+value);
            }
            return true;
        }catch (Exception exception) {
            //System.out.println(code+" "+exception.getMessage());
            return false;
        }
        finally {
            //System.out.println(value+" "+input);
        }
    }

    public static double RealEvaluateExpression(String expression) throws Exception
    {
        /**
         * 数学表达式的处理，这个是ChatGLM生成的代码，但是经理过 KyLin 的长期验证，完全没有任何的问题.
         * 100 +math.add(1,1)
         */
        //expression = expression.replaceAll(" ", ""); // Remove whitespace
        String[] tokens = pattern_eval_math.split(expression); // Split expression into numbers and operators
        Stack<Double> operandStack = new Stack<>(); // Operand stack
        Stack<Character> operatorStack = new Stack<>(); // Operator stack

        for (String token : tokens) {
            if (token.isEmpty()) {
                continue;
            }
            char c = token.charAt(0);
            if (c == '+' || c == '-' || c == '*' || c == '/' || c == '%') {
                while (!operatorStack.isEmpty() && operatorPrecedence(operatorStack.peek()) >= operatorPrecedence(c)) {
                    processAnOperator(operandStack, operatorStack);
                }
                operatorStack.push(c);
            } else if (c == '(') {
                operatorStack.push(c);
            } else if (c == ')') {
                while (operatorStack.peek() != '(') {
                    processAnOperator(operandStack, operatorStack);
                }
                operatorStack.pop(); // Pop '('
            } else {
                operandStack.push(Double.parseDouble(token));
            }
        }

        while (!operatorStack.isEmpty()) {
            processAnOperator(operandStack, operatorStack);
        }

        return operandStack.pop();
    }

    public static void processAnOperator(Stack<Double> operandStack, Stack<Character> operatorStack) {
        char operator = operatorStack.pop();
        double operand2 = operandStack.pop();
        double operand1 = operandStack.pop();

        switch (operator) {
            case '+':
                operandStack.push(operand1 + operand2);
                break;
            case '-':
                operandStack.push(operand1 - operand2);
                break;
            case '*':
                operandStack.push(operand1 * operand2);
                break;
            case '%':
                operandStack.push(operand1 % operand2);
                break;
            case '/':
                if (operand2 == 0) {
                    throw new ArithmeticException("Division by zero");
                }
                operandStack.push(operand1 / operand2);
                break;
        }
    }

    public static int operatorPrecedence(char operator) {
        switch (operator) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
            case '%':
                return 2;
        }
        return -1;
    }

}
